package demo;

import com.utils.util.Rsa;
import lombok.SneakyThrows;
import org.apache.commons.lang3.RandomStringUtils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 一键替换 resources 资源文件 RSA 公钥、私钥对 和 AES 密钥
 *
 * @author 谢长春 2022-03-21
 */
public class ReplaceSecretKey {
    @SneakyThrows
    public static void main(String[] args) {
        final List<String> envs = Arrays.asList(
                "dev", "sit", "uat", "prod"
        );
        for (String env : envs) {
            // 生成新的 公钥、私钥 对， 替换资源文件 src/main/resources/env/*.{pem|pkcs8}
            // 生成新的 公钥、私钥 对， 替换配置文件 src/main/resources/application-{env}.yml
            // spring.app.encrypt.pwd.privateKey
            // spring.app.encrypt.pwd.publicKey
            generateKeyReplaceResource(env);

            final String aesApiSecretKey = RandomStringUtils.randomAlphanumeric(32);
            final String aesDbSecretKey = RandomStringUtils.randomAlphanumeric(32);
            final String aesDbIV = RandomStringUtils.randomAlphanumeric(16);
            if (Objects.equals("dev", env)) {
                replaceAesKey(
                        "local" // local 跟 dev 环境密钥保持一致
                        , aesApiSecretKey // spring.app.encrypt.api.secretKey
                        , aesDbSecretKey // spring.app.encrypt.db.secretKey
                        , aesDbIV // spring.app.encrypt.db.ivParameterSpec
                );
            }
            replaceAesKey(
                    env
                    , aesApiSecretKey // spring.app.encrypt.api.secretKey
                    , aesDbSecretKey // spring.app.encrypt.db.secretKey
                    , aesDbIV // spring.app.encrypt.db.ivParameterSpec
            );
        }

        {
//            System.out.println("a/c11".replaceAll("/", "\\\\/"));
//            final Process process = Runtime.getRuntime().exec(
//                    new String[]{"/bin/sh", "-c", String.format(
//                            "perl -pi -e 's/privateKey:.*# spring.app.encrypt.pwd.privateKey/privateKey: \"%s\" # spring.app.encrypt.pwd.privateKey/g' %s "
//                            , "a/c+11=".replaceAll("/", "\\\\/")
//                            , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", "local")).toAbsolutePath()
//                    )}
//            );
//            process.waitFor();
//            final InputStream inputStream = process.getInputStream();
//            final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//            System.out.println(bufferedReader.readLine());
        }
    }

    @SneakyThrows
    public static void replaceAesKey(final String env, final String aesApiSecretKey, final String aesDbSecretKey, final String aesDbIV) {
        System.out.println("【" + env + "】spring.app.encrypt.api.secretKey：" + aesApiSecretKey);
        System.out.println("【" + env + "】spring.app.encrypt.db.secretKey：" + aesDbSecretKey);
        System.out.println("【" + env + "】spring.app.encrypt.db.ivParameterSpec：" + aesDbIV);
        Runtime.getRuntime().exec(
                // spring.app.encrypt.api.secretKey: 替换值
                new String[]{"/bin/sh", "-c", String.format(
                        "perl -pi -e 's/secretKey:.*# spring.app.encrypt.api.secretKey/secretKey: \"%s\" # spring.app.encrypt.api.secretKey/g' %s "
                        , aesApiSecretKey
                        , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", env)).toAbsolutePath()
                )}
        ).waitFor();
        Runtime.getRuntime().exec(
                // spring.app.encrypt.db.secretKey: 替换值
                new String[]{"/bin/sh", "-c", String.format(
                        "perl -pi -e 's/secretKey:.*# spring.app.encrypt.db.secretKey/secretKey: \"%s\" # spring.app.encrypt.db.secretKey/g' %s "
                        , aesDbSecretKey
                        , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", env)).toAbsolutePath()
                )}
        ).waitFor();
        Runtime.getRuntime().exec(
                // spring.app.encrypt.db.ivParameterSpec: 替换值
                new String[]{"/bin/sh", "-c", String.format(
                        "perl -pi -e 's/ivParameterSpec:.*# spring.app.encrypt.db.ivParameterSpec/ivParameterSpec: \"%s\" # spring.app.encrypt.db.ivParameterSpec/g' %s "
                        , aesDbIV
                        , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", env)).toAbsolutePath()
                )}
        ).waitFor();
    }

    /**
     * 生成新的 公钥、私钥 对， 替换资源文件 main-module/src/main/resources/env/*.{pem|pkcs8}
     */
    @SneakyThrows
    public static void generateKeyReplaceResource(final String env) {
        final Rsa.KeyStore keys = Rsa.createKeys();
        final String privateKey = keys.getPrivateKey();
        final String publicKey = keys.getPublicKey();
        System.out.println("【" + env + "】spring.app.encrypt.pwd.privateKey 私钥：" + privateKey);
        System.out.println("【" + env + "】spring.app.encrypt.pwd.publicKey 公钥：" + publicKey);
        if (Objects.equals("dev", env)) {
            Runtime.getRuntime().exec(
                    // spring.app.encrypt.pwd.privateKey: 替换值
                    new String[]{"/bin/sh", "-c", String.format(
                            "perl -pi -e 's/privateKey:.*# spring.app.encrypt.pwd.privateKey/privateKey: \"%s\" # spring.app.encrypt.pwd.privateKey/g' %s "
                            , privateKey.replaceAll("/", "\\\\/")
                            , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", "local")).toAbsolutePath()
                    )}
            ).waitFor();
            Runtime.getRuntime().exec(
                    // spring.app.encrypt.pwd.publicKey: 替换值
                    new String[]{"/bin/sh", "-c", String.format(
                            "perl -pi -e 's/publicKey:.*# spring.app.encrypt.pwd.publicKey/publicKey: \"%s\" # spring.app.encrypt.pwd.publicKey/g' %s "
                            , publicKey.replaceAll("/", "\\\\/")
                            , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", "local")).toAbsolutePath()
                    )}
            ).waitFor();
        }
        Runtime.getRuntime().exec(
                // spring.app.encrypt.pwd.privateKey: 替换值
                new String[]{"/bin/sh", "-c", String.format(
                        "perl -pi -e 's/privateKey:.*# spring.app.encrypt.pwd.privateKey/privateKey: \"%s\" # spring.app.encrypt.pwd.privateKey/g' %s "
                        , privateKey.replaceAll("/", "\\\\/")
                        , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", env)).toAbsolutePath()
                )}
        ).waitFor();
        Runtime.getRuntime().exec(
                // spring.app.encrypt.pwd.publicKey: 替换值
                new String[]{"/bin/sh", "-c", String.format(
                        "perl -pi -e 's/publicKey:.*# spring.app.encrypt.pwd.publicKey/publicKey: \"%s\" # spring.app.encrypt.pwd.publicKey/g' %s "
                        , publicKey.replaceAll("/", "\\\\/")
                        , Paths.get(String.format("main-module/src/main/resources/application-%s.yml", env)).toAbsolutePath()
                )}
        ).waitFor();

        Files.write(Paths.get(String.format("main-module/src/main/resources/env/%s/private.pkcs8", env)), privateKey.getBytes());
        Files.write(Paths.get(String.format("main-module/src/main/resources/env/%s/public.pkcs8", env)), publicKey.getBytes());
        Files.write(
                Paths.get(String.format("main-module/src/main/resources/env/%s/private.pem", env)),
                ("-----BEGIN RSA PRIVATE KEY-----\n"
                        + privateKey.replaceAll("(.{64})", "$1\n")
                        + "\n-----END RSA PRIVATE KEY-----"
                ).getBytes()
        );
        Files.write(
                Paths.get(String.format("main-module/src/main/resources/env/%s/public.pem", env)),
                ("-----BEGIN RSA PUBLIC KEY-----\n"
                        + publicKey.replaceAll("(.{64})", "$1\n")
                        + "\n-----END RSA PUBLIC KEY-----"
                ).getBytes()
        );
        String privateContent = Rsa.encryptByPrivateKey("zh_CN 中文", privateKey);
        System.out.println("【" + env + "】私钥加密：" + privateContent);
        System.out.println("【" + env + "】私钥加密 => 公钥解密：" + Rsa.decryptByPublicKey(privateContent, publicKey));
        String publicContent = Rsa.encryptByPublicKey("zh_CN 中文", publicKey);
        System.out.println("【" + env + "】公钥加密：" + publicContent);
        System.out.println("【" + env + "】公钥加密 => 私钥解密：" + Rsa.decryptByPrivateKey(publicContent, privateKey));
    }
}
